using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Threading;

namespace WpfTreeGridTest
{
    public static class WidthSynchronizer
    {
        // 存储源元素的宽度值（按索引）
        private static readonly Dictionary<string, double> _sourceWidths = new Dictionary<string, double>();

        // 存储目标元素的弱引用（按索引）
        private static readonly Dictionary<string, List<WeakReference>> _targetElements =
            new Dictionary<string, List<WeakReference>>();

        // 用于延迟更新操作的计时器
        private static readonly DispatcherTimer _updateTimer = new DispatcherTimer
        {
            Interval = TimeSpan.FromMilliseconds(50)
        };

        static WidthSynchronizer()
        {
            _updateTimer.Tick += (s, e) => _updateTimer.Stop();
        }

        #region 源索引附加属性

        public static readonly DependencyProperty SourceIndexProperty =
            DependencyProperty.RegisterAttached("SourceIndex", typeof(string), typeof(WidthSynchronizer),
                new PropertyMetadata(string.Empty, OnSourceIndexChanged));

        public static string GetSourceIndex(DependencyObject obj) => (string)obj.GetValue(SourceIndexProperty);
        public static void SetSourceIndex(DependencyObject obj, string value) => obj.SetValue(SourceIndexProperty, value);

        private static void OnSourceIndexChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is FrameworkElement element && e.NewValue is string index)
            {
                // 当索引变化时更新宽度
                UpdateElementWidth(element, index);
            }
        }

        #endregion

        #region 源宽度附加属性

        public static readonly DependencyProperty SourceWidthProperty =
            DependencyProperty.RegisterAttached("SourceWidth", typeof(double), typeof(WidthSynchronizer),
                new PropertyMetadata(0.0, OnSourceWidthChanged));

        public static double GetSourceWidth(DependencyObject obj) => (double)obj.GetValue(SourceWidthProperty);

        public static void SetSourceWidth(DependencyObject obj, double value) =>
            obj.SetValue(SourceWidthProperty, value);

        private static void OnSourceWidthChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (!(d is FrameworkElement element) || !(e.NewValue is double width)) return;
            // 当源宽度变化时更新存储的宽度值
            var index = GetSourceIndex(element);
            if (!string.IsNullOrWhiteSpace(index))
            {
                _sourceWidths[index] = width;

                // 延迟更新以避免频繁刷新
                _updateTimer.Stop();
                _updateTimer.Tick -= UpdateTimer_Tick;
                _updateTimer.Tick += UpdateTimer_Tick;
                _updateTimer.Start();
            }
        }

        private static void UpdateTimer_Tick(object sender, EventArgs e)
        {
            _updateTimer.Stop();
            _updateTimer.Tick -= UpdateTimer_Tick;

            // 更新所有目标元素
            foreach (var index in _sourceWidths.Keys.ToList())
            {
                UpdateTargetsForIndex(index);
            }
        }

        #endregion

        #region 目标索引附加属性

        public static readonly DependencyProperty TargetIndexProperty =
            DependencyProperty.RegisterAttached("TargetIndex", typeof(string), typeof(WidthSynchronizer),
                new PropertyMetadata(string.Empty, OnTargetIndexChanged));

        public static string GetTargetIndex(DependencyObject obj) => (string)obj.GetValue(TargetIndexProperty);
        public static void SetTargetIndex(DependencyObject obj, string value) => obj.SetValue(TargetIndexProperty, value);

        private static void OnTargetIndexChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (!(d is FrameworkElement element)) return;
            var oldIndex = e.OldValue.ToString();
            var newIndex = e.NewValue.ToString();

            // 从旧索引中移除
            if (!string.IsNullOrWhiteSpace(oldIndex) && _targetElements.TryGetValue(oldIndex, out var targetElement))
            {
                targetElement.RemoveAll(wr =>
                    !wr.IsAlive || Equals(wr.Target, element));
            }

            // 添加到新索引
            if (!string.IsNullOrWhiteSpace(newIndex))
            {
                if (!_targetElements.ContainsKey(newIndex))
                {
                    _targetElements[newIndex] = new List<WeakReference>();
                }

                // 检查是否已存在引用
                if (!_targetElements[newIndex].Any(wr =>
                        wr.IsAlive && Equals(wr.Target, element)))
                {
                    _targetElements[newIndex].Add(new WeakReference(element));
                }

                // 更新元素宽度
                UpdateElementWidth(element, newIndex);
            }
        }

        #endregion

        #region 宽度同步方法

        private static void UpdateElementWidth(FrameworkElement element, string index)
        {
            element.Width = _sourceWidths.TryGetValue(index, out var width) ? width : double.NaN; // 使用自动宽度
        }

        private static void UpdateTargetsForIndex(string index)
        {
            if (!_targetElements.TryGetValue(index, out var references)) return;
            // 清理无效引用
            references.RemoveAll(wr => !wr.IsAlive);

            foreach (var weakRef in references.ToList())
            {
                if (weakRef.IsAlive && weakRef.Target is FrameworkElement element)
                {
                    UpdateElementWidth(element, index);
                }
            }

            // 如果列表为空，移除该索引
            if (references.Count == 0)
            {
                _targetElements.Remove(index);
            }
        }

        #endregion
    }
}